/**
 * Created by henian.xu on 2017/7/5 0005.
 * jquery插件开发模板
 */

define(
    [
        'jquery'
    ],
    function ($) {
        var
            plugName = 'xDropdown',
            plugVersion = '0.1.0',
            $win = $(window),
            $doc = $(document),
            $body = $(document.body);

        /**
         * 定义插件类构造函数
         * @param el
         * @param options
         */
        $[plugName] = function (el, options) {
            this.version = plugVersion;
            this.$target = $(el);
            this.$target.data('x-' + plugName, this);// 缓存实例对象
            var
                _super = this,
                cfg = $.extend(true, {}, $[plugName].defaults, options),
                methods = {};

            //缓存常用少变更的 jQ 对象
            this.$menu = this.$target.children('.x-menu');

            // 私有方法
            methods = {
                /**
                 * 插件初始化
                 */
                init: function () {
                    methods.initElement();
                    methods.initEvent();
                    methods.lazyHandle();
                },
                lazyHandle: function () {
                    if (cfg.isLazy === null)return;
                    var event = cfg.isLazy;
                    $(event.target).trigger(event);
                },
                initElement: function () {
                    cfg.trigger = cfg.trigger || _super.$target.data('trigger') || 'hover';
                    cfg.placement = cfg.placement || _super.$menu.data('placement') || 'bottomLeft';
                    // 菜单移出原来节点位置
                    var $node = $('<div class="x-dropdown-popup" style="position:absolute;top:0;left:0;width:100%;"></div>');
                    _super.$menu.hide();
                    $node.append(_super.$menu);
                    $body.append($node);
                },
                initEvent: function () {
                    _super.$target.on('mouseenter', function (e) {
                        return methods.onHover.call(this, e)
                    });
                    _super.$target.on('mouseleave', function (e) {
                        return methods.onLeave.call(this, e)
                    });
                    _super.$target.on('click', function (e) {
                        return methods.onClick.call(this, e)
                    });
                    _super.$menu.on('mouseenter', function (e) {
                        return methods.onMenuHover.call(this, e);
                    });
                    _super.$menu.on('mouseleave', function (e) {
                        return methods.onMenuLeave.call(this, e);
                    });
                    _super.$menu.on('click', function (e) {
                        return methods.onMenuClick.call(this, e);
                    });
                    $win.on('resize', function (e) {
                        return methods.onWinResize.call(this, e);
                    })
                },
                onMenuHover: function (event) {
                    if (cfg.trigger !== 'hover')return;
                    _super.$menu._hover = true;
                },
                onMenuLeave: function (event) {
                    if (cfg.trigger !== 'hover')return;
                    _super.$menu._hover = false;
                    setTimeout(function () {
                        if (!_super.$menu._hover && !_super.$target._hover) {
                            methods.fold();
                        }
                    }, 200);
                },
                onMenuClick: function () {
                    var $eTarget = $(event.target);
                    if ($eTarget.closest('.x-menu-item').children('.x-menu-submenu').length)return;
                    methods.fold();
                },
                onHover: function (event) {
                    if (cfg.trigger !== 'hover')return;
                    _super.$target._hover = true;
                    methods.extend();
                },
                onLeave: function (event) {
                    if (cfg.trigger !== 'hover')return;
                    _super.$target._hover = false;
                    setTimeout(function () {
                        if (!_super.$menu._hover && !_super.$target._hover) {
                            methods.fold();
                        }
                    }, 200);
                },
                onClick: function (event) {
                    var $eTarget = $(event.target);
                    if (
                        cfg.trigger !== 'click' ||
                        (
                            $eTarget.closest('.x-menu').get(0) === _super.$menu.get(0) &&
                            $eTarget.closest('.x-menu-item').children('.x-menu-submenu').length
                        )
                    )return;
                    _super.$target.hasClass('extend') ?
                        methods.fold() : methods.extend();

                    methods.clickOutSide(function (e) {
                        methods.fold();
                    });
                },
                onWinResize: function () {
                    if (!_super.$target.isExtend)return;
                    methods.resetPlacement();
                },
                getTargetRect: function () {
                    var
                        newOffset = _super.$target.offset(),
                        oldOffset = _super.$target._offset || {};
                    _super.$target._offset = newOffset;

                    return {
                        x: newOffset.left,
                        y: newOffset.top,
                        w: _super.$target.outerWidth(),
                        h: _super.$target.outerHeight(),
                        c: oldOffset.top !== newOffset.top || oldOffset.left !== newOffset.left // 是否改变位置
                    };
                },
                resetPlacement: function () {
                    var rect = methods.getTargetRect();
                    if (!rect.c)return;
                    var
                        mW = _super.$menu.outerWidth(),
                        mH = _super.$menu.outerHeight();
                    _super.$menu.css({
                        position: 'absolute',
                        left: function () {
                            var val;
                            switch (cfg.placement) {
                                case 'topRight':
                                case 'bottomRight':
                                    val = rect.x + rect.w - mW;
                                    break;
                                case 'topCenter':
                                case 'bottomCenter':
                                    val = rect.x + (rect.w - mW) / 2;
                                    break;
                                case 'topLeft':
                                case 'bottomLeft':
                                default:
                                    val = rect.x;
                                    break;
                            }
                            return val;
                        },
                        top: function () {
                            var val;
                            switch (cfg.placement) {
                                case 'topRight':
                                case 'topCenter':
                                case 'topLeft':
                                    val = rect.y - mH;
                                    break;
                                case 'bottomRight':
                                case 'bottomCenter':
                                case 'bottomLeft':
                                default:
                                    val = rect.y + rect.h;
                                    break;
                            }
                            return val;
                        }
                    });
                },
                extend: function () {
                    _super.$target.addClass('extend');
                    _super.$target.isExtend = true;
                    methods.resetPlacement();
                    _super.$menu.show();
                },
                fold: function () {
                    _super.$target.removeClass('extend');
                    _super.$target.isExtend = false;
                    _super.$menu.hide();
                },
                /**
                 * 是否是本例子节点
                 * @param $el
                 * @returns {boolean}
                 */
                ischildren: function ($el) {
                    var valids = [_super.$target, _super.$menu], returnVal = false;
                    for (var i = 0, $item; $item = valids[i++];) {
                        returnVal = $el.closest('.' + $item.attr('class').split(' ').join('.')).get(0) === $item.get(0);
                        if (returnVal)break;
                    }
                    return returnVal;
                },
                /**
                 * 在元素外面点击
                 * @param delay
                 */
                clickOutSide: (function () {
                    var isRun = false, _callBack = null;
                    var fn = function (e) {
                        if (methods.ischildren($(e.target)))return;
                        $doc.off('click', fn);
                        _callBack(e);
                        isRun = false;
                    };
                    return function (callBack) {
                        if (isRun)return;
                        isRun = true;
                        _callBack = callBack;
                        $doc.on('click', fn);
                    }
                })()
            };

            methods.init();
        };

        // 公开方法
        var plugPro = $[plugName].prototype; // 简化原形

        /**
         * 注册插件
         * @param options
         * @returns {*}
         */
        $.fn[plugName] = function (options) {
            options = options || {};
            if ($.type(options) === 'object') {
                return this.each(function () {
                    var $plug = $(this).data('x-' + plugName);
                    if ($plug === undefined) {
                        new $[plugName](this, options);
                    } else {
                        // 实例对象已经存在
                    }
                });
            } else {
                // 其它参数类型
            }
        };

        // 默认设置
        $[plugName].defaults = {
            isLazy: null, // 一个事件对象
            trigger: null, // 触发方式 click/hover 默认: hover
            placement: null // 菜单弹出位置，默认：bottomLeft 所有值如下：bottomLeft/bottomCenter/bottomRight/topLeft/topCenter/topRight
        };

        // 惰性实例化插件 mouseleave
        $doc.on('click mouseenter', '.x-dropdown', function (e) {
            var
                $this = $(this);
            if ($this.data('x-' + plugName) !== undefined)return;
            new $[plugName](this, {isLazy: e});
        });

        return $[plugName];
    }
);
